/*
 * Package il.ac.biu.cs.grossmm.impl.activeData
 * File SqlPropertyMapping.java
 * 
 * This is a part of presence service framework prototype. 
 * See javadoc for more information.
 *  
 * Copyright (C) 2006 Grossmann Mark
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.

 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */
package il.ac.biu.cs.grossmm.impl.activeData;

import il.ac.biu.cs.grossmm.api.data.Property;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

public abstract class SqlPropertyMapping {
	final Property property;

	abstract void set(PreparedStatement ps, int n, Object value)
			throws Exception;

	abstract Object get(ResultSet rs, int n) throws Exception;

	abstract String getSqlType();

	protected SqlPropertyMapping(Property property) {
		this.property = property;
	}

	Property getPropertyType() {
		return property;
	}

	boolean isUnique() {
		return property.isUnique();
	}

	static SqlPropertyMapping create(Property property) {
		Class clazz = property.getValueClass();

		if (clazz.equals(String.class))
			return new StringMapping(property);

		if (clazz.equals(Integer.class))
			return new IntegerMapping(property);

		if (clazz.equals(Boolean.class))
			return new BooleanMapping(property);

		return new BytesMapping(property);
	}

	static class BytesMapping extends SqlPropertyMapping {
		public BytesMapping(final Property property) {
			super(property);
		}

		@Override
		void set(PreparedStatement ps, int n, Object value) throws Exception {
			ByteArrayOutputStream bos = new ByteArrayOutputStream();
			ObjectOutputStream oos = new ObjectOutputStream(bos);

			oos.writeObject(value);

			byte[] bytes = bos.toByteArray();
			oos.close();

			ps.setBytes(n, bytes);
		}

		@Override
		Object get(ResultSet rs, int n) throws Exception {
			byte[] bytes = rs.getBytes(n);

			if (bytes == null)
				return null;

			ByteArrayInputStream bis = new ByteArrayInputStream(bytes);

			ObjectInputStream ois = new ObjectInputStream(bis);

			Object o = ois.readObject();
			ois.close();

			return o;
		}

		@Override
		String getSqlType() {
			return "VARBINARY";
		}
	}

	static class StringMapping extends SqlPropertyMapping {
		public StringMapping(Property property) {
			super(property);
		}

		@Override
		void set(PreparedStatement ps, int n, Object value) throws Exception {
			String s = (String) value;
			ps.setString(n, s);
		}

		@Override
		Object get(ResultSet rs, int n) throws Exception {
			return rs.getString(n);
		}

		@Override
		String getSqlType() {
			return "VARCHAR";
		}
	}

	static class BooleanMapping extends SqlPropertyMapping {
		public BooleanMapping(Property property) {
			super(property);
		}

		@Override
		void set(PreparedStatement ps, int n, Object value) throws Exception {
			Boolean b = (Boolean) value;
			ps.setBoolean(n, b);
		}

		@Override
		Object get(ResultSet rs, int n) throws Exception {
			return rs.getBoolean(n);
		}

		@Override
		String getSqlType() {
			return "BOOLEAN";
		}
	}

	static class IntegerMapping extends SqlPropertyMapping {
		public IntegerMapping(Property property) {
			super(property);
		}

		@Override
		void set(PreparedStatement ps, int n, Object value) throws Exception {
			Integer i = (Integer) value;
			ps.setInt(n, i);
		}

		@Override
		Object get(ResultSet rs, int n) throws Exception {
			return rs.getInt(n);
		}

		@Override
		String getSqlType() {
			return "BOOLEAN";
		}
	}

}
